//
//  RequestDataModel.swift
//  TSKit
//
//  Created by chenyusen on 2018/2/6.
//  Copyright © 2018年 TechSen. All rights reserved.
//

import Foundation
import Moya
import SwiftyJSON


private var pagedKey: Void?

open class PageProvider {
    public var pageSizeName = "pageSize"
    public var pageName = "page"
    public var currentPage: Int = 1
    public var pageSize: Int = 20
    
    public init() {
    }
}

public class RequestDataModel: NSObject {
    
     internal class Request {
        var targetType: TargetType
        var cancelable: Cancellable?
        var json: JSON?
        var error: Error?
        
        init(_ targetType: TargetType) {
            self.targetType = targetType
        }
    }
    
    private var requests: [Request] = []
    
    private var isLoadedFlag = false
    private var isLoadingFlag = false
    private var isLoadingMoreFlag = false
    
    private var loadFromFile = false
    
    private var pageProvider: PageProvider?
    public  var startPage = 1
    
    private var cancelToRequestHandler: (() -> ())? = nil
    
    public var loadedTime: Date?
    
    public var delegates = NSHashTable<AnyObject>.weakObjects()
    
    /// 初始化一个网络请求
    ///
    /// - Parameters:
    ///   - targetType: 基于Moya的网络请求目标
    ///   - subTargetTypes:基于Moya的子网络请求目标(由于一个页面的数据可能是由多个接口组成)
    ///   - loadFromFile: 是否先从缓存文件加载数据
    ///   - pageProvider: 是否支持分页
    public init(_ targetType: TargetType,
                subTargetTypes: [TargetType]? = nil,
                loadFromFile: Bool = false,
                pageProvider: PageProvider? = nil) {
            self.pageProvider = pageProvider
            requests.append(Request(targetType))
        
            if let subTargetTypes = subTargetTypes {
                requests.append(contentsOf: subTargetTypes.map { Request($0) } )
            }
            self.loadFromFile = loadFromFile
    }
}

extension RequestDataModel: DataModelCompatible {
  
    public var isLoaded: Bool {
        return loadedTime != nil
    }
    
    public var isLoading: Bool {
        return isLoadingFlag
    }
    
    public var isLoadingMore: Bool {
        return isLoadingMoreFlag
    }
    
    public var isOutdated: Bool {
        return false
    }
    
    public func load(more: Bool = false) {
        
        
        if !more { // 如果不是加载更多,且当前的targetType支持分页,则当前页数设置为1
            pageProvider?.currentPage = startPage
        }
        
        // 如果需要先从缓存文件加载
        if loadFromFile && !isLoaded && !more {
            
            let caches: [JSON] = requests.flatMap {
                if let data = NetworkManager.default.cache($0.targetType) {
                    return try? JSON(data: data)
                }
                return nil
            }
            
            if caches.count == requests.count { // 如果之前所有接口都有缓存,才采用缓存数据
                didFinishLoad(data: caches.count == 1 ? caches.first : caches)
            }
        }

        let reqeustHandler = { [weak self] in
            guard let sSelf = self else { return }
            // 如果是加载更多,那么只请求第一个targetType
            
            
            // 通知所有订阅者数据开始加载
            sSelf.isLoadingFlag = true
            
            sSelf.isLoadingMoreFlag = false
            if sSelf.pageProvider != nil && more {
                sSelf.isLoadingMoreFlag = true
            }
            
            sSelf.didStartLoad()
            let group = DispatchGroup()
            for request in sSelf.requests {
                group.enter()
//                let name = "\(request.targetType)".hashValue
                
                let cancelable = NetworkManager.default.request(targetType: request.targetType, success: { [weak self] (json) in
                    guard let sSelf = self else { return }
                    if sSelf.loadFromFile {
                        do {
                            let jsonData = try json.rawData()
                            NetworkManager.default.store(jsonData, with: request.targetType)
                        } catch _ {}
                    }
                    
                    request.json = json
                    group.leave()
                    }, failure: { (error) in
                        request.error = error
                        group.leave()
                })
                request.cancelable = cancelable
                
                if more { break } // 如果是加载更多,则只请求主target
            }
            
            
            // 所有请求结束回调
            group.notify(queue: .main) { [weak self] in
                guard let sSelf = self else { return }
                sSelf.isLoadingFlag = false
                sSelf.isLoadingMoreFlag = false
                let errorRequests = sSelf.requests.filter { $0.error != nil }
                if errorRequests.count > 0 {
                    // 如果错误中有一个请求是因为主动取消造成的,则认为此次请求被主动取消
                    if errorRequests.first(where: { ($0.error! as NSError).code == NSURLErrorCancelled }) != nil {
                        sSelf.didCancelLoad()
                        sSelf.cancelToRequestHandler?()
                    } else {
                        // 否则认为此次请求失败
                        sSelf.didFaildLoad(error: (errorRequests.first?.error)!)
                    }
                } else { // 如果请求都是正确的, 那么认为此次请求成功
                    if !more  {
                        sSelf.loadedTime = Date()
                    }
                    sSelf.pageProvider?.currentPage += 1
                    let response = sSelf.requests.map { $0.json ?? JSON() }
                    sSelf.didFinishLoad(data: response.count == 1 ? response.first : response)
                }
                sSelf.cancelToRequestHandler = nil
            }
        }
        
        
        // 先取消之前所有的请求
        if isLoadingFlag {
            cancelToRequestHandler = {
                reqeustHandler()
            }
            cancel()
        } else {
            reqeustHandler()
        }
    }
    
    public func cancel() {
        if isLoadingFlag {
            requests.forEach { $0.cancelable?.cancel(); $0.cancelable = nil; $0.error = nil }
        }
    }
}
